From 74c22601baad83cc9bc0fddb98f15d7abaa52c67 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 17 Jun 2025 11:16:17 +0200 Subject: [PATCH] wireless: add MLO support to example scripts Signed-off-by: Felix Fietkau --- examples/wireless-device.uc | 28 ++++++++++++++++++++ examples/wireless.uc | 48 ++++++++++++++++++++++++++++++++++- examples/wireless/mac80211.sh | 12 +++++++++ 3 files changed, 87 insertions(+), 1 deletion(-) diff --git a/examples/wireless-device.uc b/examples/wireless-device.uc index f6db09c..b0faef1 100644 --- a/examples/wireless-device.uc +++ b/examples/wireless-device.uc @@ -12,6 +12,9 @@ const NOTIFY_CMD_SET_RETRY = 4; const DEFAULT_RETRY = 3; const DEFAULT_SCRIPT_TIMEOUT = 30 * 1000; +export const mlo_name = "#mlo"; + +let mlo_wdev; let wdev_cur; let wdev_handler = {}; let wdev_script_task, wdev_script_timeout; @@ -59,6 +62,23 @@ function handle_link(dev, data, up) }); } +function wdev_mlo_fixup(config) +{ + if (!mlo_wdev) + return; + + for (let name, iface in config.interfaces) { + let config = iface.config; + + if (config.mode != "link") + continue; + + let mlo_config = mlo_wdev.handler_data[iface.name]; + if (mlo_config && mlo_config.ifname) + config.ifname = mlo_config.ifname; + } +} + function wdev_config_init(wdev) { let data = wdev.data; @@ -177,6 +197,9 @@ function handler_sort_fn(a, b) function __run_next_handler_name() { + if (wdev_handler[mlo_name]) + return mlo_name; + return sort(keys(wdev_handler), handler_sort_fn)[0]; } @@ -194,6 +217,8 @@ function __run_next_handler() let cb = wdev_cur.cb; wdev.dbg("run " + op); + if (name != mlo_name) + wdev_mlo_fixup(wdev.handler_config); wdev.handler_config.data = wdev.handler_data[wdev.name]; wdev_script_task = netifd.process({ cb: () => run_handler_cb(wdev, cb), @@ -409,6 +434,9 @@ function wdev_mark_up(wdev) if (wdev.state != "setup") return; + if (wdev.name == mlo_name) + mlo_wdev = wdev; + if (wdev.config_change) { wdev.setup(); return; diff --git a/examples/wireless.uc b/examples/wireless.uc index d75aaca..b63ec23 100644 --- a/examples/wireless.uc +++ b/examples/wireless.uc @@ -45,6 +45,7 @@ function config_init(uci) let handlers = {}; let devices = {}; let vifs = {}; + let mlo_device; let sections = { device: {}, @@ -52,6 +53,7 @@ function config_init(uci) vlan: {}, station: {}, }; + let radio_idx = {}; for (let name, data in config) { let type = data[".type"]; @@ -64,6 +66,20 @@ function config_init(uci) let list = sections[substr(type, 5)]; if (list) list[name] = data; + + if (type == "wifi-iface" && parse_bool(data.mlo)) + mlo_device = true; + } + + if (mlo_device) { + devices[wdev.mlo_name] = { + name: wdev.mlo_name, + config: { + type: "mac80211", + }, + vif: [], + }; + handlers[wdev.mlo_name] = wireless.handlers.mac80211; } for (let name, data in sections.device) { @@ -74,6 +90,9 @@ function config_init(uci) if (!handler) continue; + if (data.radio != null) + radio_idx[name] = +data.radio; + let config = parse_attribute_list(data, handler.device); devices[name] = { name, @@ -86,6 +105,12 @@ function config_init(uci) for (let name, data in sections.iface) { let dev_names = parse_array(data.device); + let mlo_vif = parse_bool(data.mlo); + let radios = map(dev_names, (v) => radio_idx[v]); + radios = filter(radios, (v) => v != null); + let radio_config = map(dev_names, (v) => devices[v].config); + if (mlo_vif) + dev_names = [ wdev.mlo_name, ...dev_names ]; for (let dev_name in dev_names) { let dev = devices[dev_name]; if (!dev) @@ -96,6 +121,12 @@ function config_init(uci) continue; let config = parse_attribute_list(data, handler.iface); + if (mlo_vif) + if (dev_name == wdev.mlo_name) + config.radio_config = radio_config; + else + config.mode = "link"; + config.radios = radios; let vif = { name, config, @@ -266,8 +297,11 @@ function wdev_call(req, cb) return cb(dev); } - for (let name, dev in wireless.devices) + for (let name, dev in wireless.devices) { + if (name == wdev.mlo_name) + continue; cb(dev); + } return 0; } @@ -308,6 +342,10 @@ const ubus_obj = { up: { args: wdev_args, call: function(req) { + let mlo_dev = wireless.devices[wdev.mlo_name]; + if (mlo_dev) + mlo_dev.start(); + return wdev_call(req, (dev) => { dev.start(); return 0; @@ -317,6 +355,10 @@ const ubus_obj = { down: { args: wdev_args, call: function(req) { + let mlo_dev = wireless.devices[wdev.mlo_name]; + if (mlo_dev) + mlo_dev.config_change = true; + return wdev_call(req, (dev) => { dev.stop(); return 0; @@ -326,6 +368,10 @@ const ubus_obj = { reconf: { args: wdev_args, call: function(req) { + let mlo_dev = wireless.devices[wdev.mlo_name]; + if (mlo_dev) + mlo_dev.update(); + return wdev_call(req, (dev) => { dev.update(); return 0; diff --git a/examples/wireless/mac80211.sh b/examples/wireless/mac80211.sh index 28e16f7..8389afa 100755 --- a/examples/wireless/mac80211.sh +++ b/examples/wireless/mac80211.sh @@ -287,6 +287,17 @@ setup_vif() { vifidx=$((vifidx + 1)) } +setup_link() { + local name="$1" + + json_select config + json_get_vars ifname + json_select .. + + echo "Add link on $radio: $ifname" +} + + drv_mac80211_cleanup() { echo "mac80211 cleanup" } @@ -296,6 +307,7 @@ drv_mac80211_setup() { radio=$1 vifidx=0 json_dump + for_each_interface "link" setup_link for_each_interface "sta ap adhoc" setup_vif wireless_set_data phy=phy0 wireless_set_up -- 2.30.2